package com.example.sfm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.sfm.exception.ObjectException;
import com.example.sfm.handler.TemplateStyleHandler;
import com.example.sfm.pojo.dto.AwardsPunishmentsDto;
import com.example.sfm.pojo.dto.AwardsPunishmentsImportDto;
import com.example.sfm.pojo.dto.AwardsPunishmentsQueryDto;
import com.example.sfm.pojo.entity.AwardsPunishments;
import com.example.sfm.mapper.AwardsPunishmentsMapper;
import com.example.sfm.pojo.entity.StudentRecords;
import com.example.sfm.pojo.vo.AwardsPunishmentsExportVo;
import com.example.sfm.pojo.vo.AwardsPunishmentsVo;
import com.example.sfm.result.PageResult;
import com.example.sfm.service.IAwardsPunishmentsService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.sfm.service.IStudentRecordsService;
import com.example.sfm.service.IUsersService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author sfm
 * @since 2025-03-07
 */
@Service
@RequiredArgsConstructor
public class AwardsPunishmentsServiceImpl extends ServiceImpl<AwardsPunishmentsMapper, AwardsPunishments>
        implements IAwardsPunishmentsService {

    private final IStudentRecordsService studentRecordsService;
    private final IUsersService usersService;

    @Override
    @Transactional
    public void createRecord(AwardsPunishmentsDto dto) {
        // 校验学生存在性
        if (!studentRecordsService.exists(new LambdaQueryWrapper<StudentRecords>().eq(StudentRecords::getUserId, dto.getStudentId()))) {
            throw new ObjectException("学生不存在");
        }

        AwardsPunishments entity = BeanUtil.copyProperties(dto, AwardsPunishments.class);
        if (!save(entity)) {
            throw new ObjectException("创建失败");
        }
    }

    @Override
    public PageResult<AwardsPunishmentsVo> listRecords(@NotNull AwardsPunishmentsQueryDto dto) {
        LambdaQueryWrapper<AwardsPunishments> wrapper = new LambdaQueryWrapper<AwardsPunishments>()
                .eq(dto.getStudentId() != null, AwardsPunishments::getStudentId, dto.getStudentId())
                .eq(dto.getType() != null, AwardsPunishments::getType, dto.getType())
                .eq(dto.getLevel() != null, AwardsPunishments::getLevel, dto.getLevel())
                .ge(dto.getStartDate() != null, AwardsPunishments::getIssuedDate, dto.getStartDate())
                .le(dto.getEndDate() != null, AwardsPunishments::getIssuedDate, dto.getEndDate())
                .orderByDesc(AwardsPunishments::getIssuedDate);

        Page<AwardsPunishments> page = page(new Page<>(dto.getPageNum(), dto.getPageSize()), wrapper);

        return new PageResult<>(page.getTotal(),
                page.getRecords().stream()
                        .map(this::convertToVo)
                        .toList());
    }

    private @NotNull AwardsPunishmentsVo convertToVo(AwardsPunishments entity) {
        AwardsPunishmentsVo vo = BeanUtil.copyProperties(entity, AwardsPunishmentsVo.class);
        vo.setTypeStr(convertType(entity.getType()))
                .setStudentName(usersService.getById(entity.getStudentId()).getFullName())
                .setLevelStr(convertLevel(entity.getLevel()));
        return vo;
    }

    @Contract(pure = true)
    private @NotNull String convertType(Integer type) {
        return type == 0 ? "奖励" : "惩罚";
    }

    @Contract(pure = true)
    private @NotNull String convertLevel(Integer level) {
        return level == null ? "奖励" : level == 0 ? "一般" : "严重";
    }

    @Override
    @Transactional
    public void updateRecord(Integer id, AwardsPunishmentsDto dto) {
        AwardsPunishments entity = getById(id);
        if (entity == null) throw new ObjectException("记录不存在");

        // 禁止修改学生ID
        if (!entity.getStudentId().equals(dto.getStudentId())) {
            throw new ObjectException("不可修改关联学生");
        }

        BeanUtil.copyProperties(dto, entity, "studentId");
        if (!updateById(entity)) {
            throw new ObjectException("更新失败");
        }
    }

    @Override
    @Transactional
    public void deleteRecords(List<Integer> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new ObjectException("ID列表不能为空");
        }
        List<Integer> distinctIds = ids.stream().distinct().toList();
        if (!removeBatchByIds(distinctIds)) {
            throw new ObjectException("删除失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importFromExcel(@NotNull MultipartFile file) {
        try {
            List<AwardsPunishmentsImportDto> importData = EasyExcel.read(file.getInputStream())
                    .head(AwardsPunishmentsImportDto.class)
                    .sheet()
                    .doReadSync();

            System.out.println(importData);

            List<AwardsPunishments> records = importData.stream()
                    .map(this::convertImportData)
                    .collect(Collectors.toList());

            if (!saveBatch(records)) {
                throw new ObjectException("批量导入失败");
            }
        } catch (IOException e) {
            throw new ObjectException("文件读取失败");
        }
    }

    private AwardsPunishments convertImportData(@NotNull AwardsPunishmentsImportDto dto) {
        // 根据学号查询学生ID
        Integer studentId = studentRecordsService.lambdaQuery()
                .eq(StudentRecords::getStudentNumber, dto.getStudentNumber())
                .oneOpt()
                .orElseThrow(() -> new ObjectException("学号不存在: " + dto.getStudentNumber()))
                .getUserId();

        return new AwardsPunishments()
                .setStudentId(studentId)
                .setType(dto.getType())
                .setLevel(dto.getLevel())
                .setReason(dto.getReason())
                .setName(dto.getName())
                .setIssuedDate(dto.getIssuedDate());
    }

    @Override
    public void exportExcel(@NotNull HttpServletResponse response, AwardsPunishmentsQueryDto dto) {
        try {
            List<AwardsPunishmentsExportVo> data = list().stream().map(aw -> BeanUtil.copyProperties(aw, AwardsPunishmentsExportVo.class)
                    .setTypeStr(convertType(aw.getType()))
                    .setLevelStr(convertLevel(aw.getLevel()))
                    .setStudentName(usersService.getById(aw.getStudentId()).getFullName())).toList();

            String fileName = URLEncoder.encode("奖惩记录_" + LocalDate.now(), StandardCharsets.UTF_8);
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            EasyExcel.write(response.getOutputStream(), AwardsPunishmentsExportVo.class)
                    .registerWriteHandler(new TemplateStyleHandler())
                    .sheet("奖惩记录")
                    .doWrite(data);
        } catch (IOException e) {
            throw new ObjectException("导出失败");
        }
    }

    public Map<String, Object> getStats(Integer studentId) {
        Map<String, Object> stats = new HashMap<>();

        // 类型统计
        List<Map<String, Object>> typeStats = baseMapper.countByType(new LambdaQueryWrapper<AwardsPunishments>()
                .eq(AwardsPunishments::getStudentId, studentId));
        stats.put("typeStats", typeStats.stream()
                .collect(Collectors.toMap(
                        m -> convertType((Integer) m.get("type")),
                        m -> m.get("count"))
                ));

        // 等级统计
        List<Map<String, Object>> levelStats = baseMapper.countByLevel(new LambdaQueryWrapper<AwardsPunishments>()
                .eq(AwardsPunishments::getStudentId, studentId));
        stats.put("levelStats", levelStats.stream()
                .collect(Collectors.toMap(
                        m -> convertLevel((Integer) m.get("level")),
                        m -> m.get("count"))
                ));

        return stats;
    }
}
